/**
 * Socket.io配置
 * 处理实时消息和状态更新
 */
const socketIO = require('socket.io');
const jwt = require('jsonwebtoken');
const User = require('./models/user');
const Message = require('./models/message');
const Conversation = require('./models/conversation');

// 连接的用户
const connectedUsers = new Map();

// 设置Socket.io
const socketSetup = (server) => {
  const io = socketIO(server, {
    cors: {
      origin: process.env.CORS_ORIGIN || '*',
      methods: ['GET', 'POST'],
      credentials: true
    }
  });
  
  // 身份验证中间件
  io.use(async (socket, next) => {
    try {
      const token = socket.handshake.auth.token;
      
      if (!token) {
        return next(new Error('未提供认证令牌'));
      }
      
      // 验证token
      const decoded = jwt.verify(token, process.env.JWT_SECRET);
      
      // 获取用户
      const user = await User.findById(decoded.id).select('-password');
      if (!user) {
        return next(new Error('未找到用户'));
      }
      
      // 将用户信息添加到socket
      socket.user = user;
      next();
    } catch (error) {
      return next(new Error('认证失败'));
    }
  });
  
  // 连接事件
  io.on('connection', async (socket) => {
    const user = socket.user;
    
    // 更新用户在线状态
    await User.findByIdAndUpdate(user._id, {
      isOnline: true,
      lastSeen: Date.now()
    });
    
    // 存储连接的用户
    connectedUsers.set(user._id.toString(), socket.id);
    
    // 加入自己的房间（用于私聊）
    socket.join(user._id.toString());
    
    // 广播用户上线通知
    socket.broadcast.emit('user:online', { userId: user._id });
    
    // 发送消息
    socket.on('message:send', async (data) => {
      try {
        const { conversationId, content, type = 'text' } = data;
        
        // 获取对话
        const conversation = await Conversation.findById(conversationId);
        if (!conversation) {
          return socket.emit('error', { message: '对话未找到' });
        }
        
        // 验证用户是否为对话参与者
        if (!conversation.participants.includes(user._id)) {
          return socket.emit('error', { message: '您不是此对话的参与者' });
        }
        
        // 创建消息
        const message = await Message.create({
          conversation: conversationId,
          sender: user._id,
          content,
          type,
          readBy: [user._id] // 发送者默认已读
        });
        
        // 填充发送者信息
        await message.populate('sender', 'username avatar');
        
        // 更新对话的最新消息和时间
        conversation.latestMessage = message._id;
        await conversation.save();
        
        // 获取对话参与者（除了发送者）
        const receivers = conversation.participants.filter(
          p => p.toString() !== user._id.toString()
        );
        
        // 将消息发送给所有参与者
        receivers.forEach(receiverId => {
          const receiverSocketId = connectedUsers.get(receiverId.toString());
          if (receiverSocketId) {
            io.to(receiverSocketId).emit('message:receive', message);
          }
        });
        
        // 确认消息已发送
        socket.emit('message:sent', message);
      } catch (error) {
        console.error('发送消息错误:', error);
        socket.emit('error', { message: '发送消息失败' });
      }
    });
    
    // 标记消息已读
    socket.on('message:read', async (data) => {
      try {
        const { conversationId } = data;
        
        // 获取对话
        const conversation = await Conversation.findById(conversationId);
        if (!conversation) {
          return socket.emit('error', { message: '对话未找到' });
        }
        
        // 标记所有未读消息为已读
        const updatedMessages = await Message.updateMany(
          {
            conversation: conversationId,
            sender: { $ne: user._id },
            readBy: { $ne: user._id }
          },
          {
            $addToSet: { readBy: user._id }
          }
        );
        
        // 通知发送者消息已读
        if (updatedMessages.nModified > 0) {
          // 获取对话参与者（除了当前用户）
          const sender = conversation.participants.find(
            p => p.toString() !== user._id.toString()
          );
          
          const senderSocketId = connectedUsers.get(sender.toString());
          if (senderSocketId) {
            io.to(senderSocketId).emit('message:read', {
              userId: user._id,
              conversationId
            });
          }
        }
        
        socket.emit('conversation:read', { conversationId });
      } catch (error) {
        console.error('标记消息已读错误:', error);
        socket.emit('error', { message: '标记消息已读失败' });
      }
    });
    
    // 用户正在输入
    socket.on('typing:start', (data) => {
      const { conversationId } = data;
      
      // 获取对话参与者（除了当前用户）
      Conversation.findById(conversationId)
        .then(conversation => {
          if (!conversation) return;
          
          const receiver = conversation.participants.find(
            p => p.toString() !== user._id.toString()
          );
          
          const receiverSocketId = connectedUsers.get(receiver.toString());
          if (receiverSocketId) {
            io.to(receiverSocketId).emit('typing:start', {
              userId: user._id,
              conversationId
            });
          }
        })
        .catch(error => {
          console.error('发送正在输入状态错误:', error);
        });
    });
    
    // 用户停止输入
    socket.on('typing:stop', (data) => {
      const { conversationId } = data;
      
      // 获取对话参与者（除了当前用户）
      Conversation.findById(conversationId)
        .then(conversation => {
          if (!conversation) return;
          
          const receiver = conversation.participants.find(
            p => p.toString() !== user._id.toString()
          );
          
          const receiverSocketId = connectedUsers.get(receiver.toString());
          if (receiverSocketId) {
            io.to(receiverSocketId).emit('typing:stop', {
              userId: user._id,
              conversationId
            });
          }
        })
        .catch(error => {
          console.error('发送停止输入状态错误:', error);
        });
    });
    
    // 断开连接
    socket.on('disconnect', async () => {
      if (user) {
        // 更新用户离线状态
        await User.findByIdAndUpdate(user._id, {
          isOnline: false,
          lastSeen: Date.now()
        });
        
        // 移除用户连接
        connectedUsers.delete(user._id.toString());
        
        // 广播用户离线通知
        socket.broadcast.emit('user:offline', { userId: user._id });
      }
    });
  });
  
  return io;
};

module.exports = socketSetup; 